#pragma once
#include "etcd/Client.hpp"
#include "etcd/KeepAlive.hpp"
#include "etcd/Response.hpp"
#include "etcd/Watcher.hpp"
#include "logger.hpp"
#include <functional>
namespace chat_server
{
    class Registry
    {
    public:
        using ptr = std::shared_ptr<Registry>;
        Registry(const std::string &host) : _client(std::make_shared<etcd::Client>(host)),
                                            _keep_alive(_client->leasekeepalive(3).get()),
                                            _lease_id(_keep_alive->Lease())
        {
        }
        ~Registry()
        {
            _keep_alive->Cancel();
        }
        bool registry(const std::string &key, const std::string &val)
        {
            auto response = _client->put(key, val, _lease_id).get();
            if (response.is_ok() == false)
            {
                LOG_ERROR("注册失败{}", response.error_message());
                return false;
            }
            return true;
        }

    private:
        const int LeaseKeepTime = 3;
        std::shared_ptr<etcd::Client> _client;
        /*
        设置保活时间，当注册的数据设置了保活的话那么，
        当_keep_alive生命周期结束时数据会在保活时间结束后销毁
        */
        std::shared_ptr<etcd::KeepAlive> _keep_alive;
        uint64_t _lease_id;
    };

    class Discovery
    {
    public:
        using ptr = std::shared_ptr<Discovery>;
        using NotyfiyCallBack = std::function<void(std::string, std::string)>;
        Discovery(const std::string &host, const NotyfiyCallBack &put_cb,
                  const NotyfiyCallBack &del_cb, const std::string &base_dir) : _client(std::make_shared<etcd::Client>(host)),
                                                                                _put_cb(put_cb),
                                                                                _del_cb(del_cb)
        {
            auto response = _client->ls(base_dir).get();
            if (response.is_ok() == false)
            {
                LOG_ERROR("获取数据{}", response.error_message());
            }

            size_t sz = response.keys().size();
            for (int i = 0; i < sz; ++i)
            {
                if (_put_cb)
                    _put_cb(response.key(i), response.value(i).as_string());
            }
            _watcher = std::make_shared<etcd::Watcher>(*_client.get(), base_dir,
                                                       std::bind(&Discovery::callBack, this, std::placeholders::_1), true);
        }
        ~Discovery()
        {
            _watcher->Cancel();
        }

    private:
        void callBack(const etcd::Response &response)
        {
            if (response.is_ok() == false)
            {
                LOG_ERROR("收到一个错误的通知{}", response.error_message());
                return;
            }
            for (auto &event : response.events())
            {
                if (event.event_type() == etcd::Event::EventType::PUT)
                {
                    if (_put_cb)
                        _put_cb(event.kv().key(), event.kv().as_string());
                    LOG_INFO("服务上线{}:{}", event.kv().key(), event.kv().as_string());
                }
                else if (event.event_type() == etcd::Event::EventType::DELETE_)
                {
                    if (_del_cb)
                        _del_cb(event.kv().key(), event.kv().as_string());
                    LOG_INFO("服务下线{}:{}", event.kv().key(), event.kv().as_string());
                }
            }
        }
        NotyfiyCallBack _put_cb;
        NotyfiyCallBack _del_cb;
        std::shared_ptr<etcd::Client> _client;
        std::shared_ptr<etcd::Watcher> _watcher;
    };
}
